package com.biboheart.brick.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 类BeanUtils
 * @author biboheart@qq.com
 */
public class BeanUtils {
	/**
	 * map key和value设置到bean中
	 * @param source map 对象
	 * @param target bean 对象
	 * @param scope 属性范围，只处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 被修改的属性列表
	 */
	public static List<String> copyMapToBeanProperties(Map<String, Object> source, Object target, List<String> scope, List<String> exclude) {
		if(null == source || null == target) {
			return null;
		}
		Class<?> targetClass = target.getClass();
		Field[] fields = targetClass.getDeclaredFields();
		List<String> changed = new ArrayList<>();
		for (Field field : fields) {
			field.setAccessible(true);
			String key = field.getName();
			if(!source.containsKey(key)) {
				continue;
			}
			Object val = source.get(key);
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			try {
				Object tv = field.get(target);
				if(null == tv && null == val) {
					continue;
				}
				if(null != tv && null != val) {
					if (tv.getClass().isInstance(val)) {
						if(tv.equals(val)) {
							continue;
						}
					} else {
						String tvStr = String.valueOf(tv);
						String valStr = String.valueOf(val);
						if(tvStr.equals(valStr)) {
							continue;
						}
					}
				}
				if(null == val) {
					field.set(target, null);
					changed.add(key);
					continue;
				}
				if (field.getType().isInstance(val)) {
					field.set(target, val);
					changed.add(key);
					continue;
				}
                switch (field.getType().getSimpleName()) {
                    case "Long":
                    case "long":
                        long lv;
                        try {
                            lv = Long.parseLong(String.valueOf(val));
                        } catch (NumberFormatException e) {
                            continue;
                        }
                        field.set(target, lv);
                        changed.add(key);
                        continue;
                    case "Integer":
                    case "int":
                        int iv;
                        try {
                            iv = Integer.parseInt(String.valueOf(val));
                        } catch (NumberFormatException e) {
                            continue;
                        }
                        field.set(target, iv);
                        changed.add(key);
                        continue;
                    case "String":
                    case "string":
                        field.set(target, String.valueOf(val));
                        changed.add(key);
                        continue;
                }
                field.set(target, val);
				changed.add(key);
			} catch (IllegalArgumentException | IllegalAccessException ignored) {
			}
		}
		return changed;
	}
	
	/**
	 * 把bean对象转换成map对象
	 * @param source 转换来源
	 * @param target 目标对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 设置成功的参数列表
	 */
	public static List<String> beanToMap(Object source, Map<String, Object> target, List<String> scope, List<String> exclude) {
		if(null == source || null == target) {
			return null;
		}
		Class<?> targetClass = source.getClass();
		Field[] fields = targetClass.getDeclaredFields();
		List<String> copied = new ArrayList<>();
		for (Field field : fields) {
			field.setAccessible(true);
			String key = field.getName();
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			Object value;
			try {
				value = field.get(source);
				target.put(key, value);
				copied.add(key);
			} catch (IllegalArgumentException | IllegalAccessException e) {
				target.put(key, null);
			}
		}
		return copied;
	}
	
	/**
	 * 两个map之间数据拷贝
	 * @param source 源对象
	 * @param target 目标对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 目标对象值被改变的参数名称
	 */
	public static List<String> copyMapToMap(Map<String, Object> source, Map<String, Object> target, List<String> scope, List<String> exclude) {
		List<String> copied = new ArrayList<>();
		if(null == source || null == target) {
			return copied;
		}
		if(source.isEmpty()) {
			return copied;
		}
		for(Map.Entry<String, Object> entry : source.entrySet()) {
			String key = entry.getKey();
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			Object value = entry.getValue();
			target.put(key, value);
		}
		return copied;
	}
	
	/**
	 * 两个bean对象之间数据拷贝
	 * @param source 源对象
	 * @param target 目标对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 目标对象值被改变的参数名称
	 */
	public static List<String> copy(Object source, Object target, List<String> scope, List<String> exclude) {
		if(null == source || null == target) {
			return null;
		}
		Class<?> targetClass = target.getClass();
		Class<?> sourceClass = source.getClass();
		Field[] sourceFields = sourceClass.getDeclaredFields();
		List<String> changed = new ArrayList<>();
		for(Field sourceField : sourceFields) {
			sourceField.setAccessible(true);
			String key = sourceField.getName();
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			Object val;
			try {
				val = sourceField.get(source);
			} catch (IllegalArgumentException | IllegalAccessException e) {
				continue;
			}
			try {
				Field targetField = targetClass.getDeclaredField(key);
				targetField.setAccessible(true);
				Object tval = targetField.get(target);
				if(null == tval && null == val) {
					continue;
				}
				if(null != tval && null != val) {
					if (tval.getClass().isInstance(val)) {
						if(tval.equals(val)) {
							continue;
						}
					} else {
						String tvStr = String.valueOf(tval);
						String valStr = String.valueOf(val);
						if(tvStr.equals(valStr)) {
							continue;
						}
					}
				}
				if(null == val) {
					targetField.set(target, null);
					changed.add(key);
					continue;
				}
                switch (targetField.getType().getSimpleName()) {
                    case "Long":
                    case "long":
                        long lv;
                        try {
                            lv = Long.parseLong(String.valueOf(val));
                        } catch (NumberFormatException e) {
                            continue;
                        }
                        targetField.set(target, lv);
                        changed.add(key);
                        continue;
                    case "Integer":
                    case "int":
                        int iv;
                        try {
                            iv = Integer.parseInt(String.valueOf(val));
                        } catch (NumberFormatException e) {
                            continue;
                        }
                        targetField.set(target, iv);
                        changed.add(key);
                        continue;
                    case "String":
                    case "string":
                        targetField.set(target, String.valueOf(val));
                        changed.add(key);
                        continue;
                }
                targetField.set(target, val);
				changed.add(key);
			} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
//				e.printStackTrace();
			}
		}
		return changed;
	}
	
	/**
	 * 从source覆盖target中为null的项
	 * @param source 源对象
	 * @param target 目标对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 目标对象值被改变的参数名称
	 */
	public static List<String> defaultsDeep(Object source, Object target, List<String> scope, List<String> exclude) {
		if(null == source || null == target) {
			return null;
		}
		Class<?> targetClass = target.getClass();
		Class<?> sourceClass = source.getClass();
		Field[] sourceFields = sourceClass.getDeclaredFields();
		List<String> changed = new ArrayList<>();
		for(Field sourceField : sourceFields) {
			sourceField.setAccessible(true);
			String key = sourceField.getName();
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			Object val;
			try {
				val = sourceField.get(source);
			} catch (IllegalArgumentException | IllegalAccessException e) {
//				e.printStackTrace();
				continue;
			}
			try {
				Field targetField = targetClass.getDeclaredField(key);
				targetField.setAccessible(true);
				Object tval = targetField.get(target);
				if(null != tval) {
					continue;
				}
				if(null == val) {
					targetField.set(target, null);
					changed.add(key);
					continue;
				}
                switch (targetField.getType().getSimpleName()) {
                    case "Long":
                    case "long":
                        long lv;
                        try {
                            lv = Long.parseLong(String.valueOf(val));
                        } catch (NumberFormatException e) {
                            continue;
                        }
                        targetField.set(target, lv);
                        changed.add(key);
                        continue;
                    case "Integer":
                    case "int":
                        int iv;
                        try {
                            iv = Integer.parseInt(String.valueOf(val));
                        } catch (NumberFormatException e) {
                            continue;
                        }
                        targetField.set(target, iv);
                        changed.add(key);
                        continue;
                    case "String":
                        targetField.set(target, String.valueOf(val));
                        changed.add(key);
                        continue;
                }
                targetField.set(target, val);
				changed.add(key);
			} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
//				e.printStackTrace();
			}
		}
		return changed;
	}
	
	/**
	 * 将Integer|Long属性值为NULL的设为0
	 * @param source 源对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 */
	public static void compareObjIntegerValue(Object source, List<String> scope, List<String> exclude) {
		Class<?> srcClass = source.getClass();
		Field[] fields = srcClass.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			String key = field.getName();
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			try {
				Object val = field.get(source);
				if(field.getType().getSimpleName().equals("Integer") && null == val) {
					field.set(source, 0);
				}
				if(field.getType().getSimpleName().equals("Long") && null == val) {
					field.set(source, 0L);
				}
			} catch (IllegalArgumentException | IllegalAccessException e) {
//				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 将scope指点的属性的值从22,33,55转换成(22)(33)(55)
	 * @param source 对象
	 * @param scope 要转换的属性名称
	 */
	public static void compareObjCommaString2BraceString(Object source, List<String> scope) {
		Class<?> srcClass = source.getClass();
		if(null == scope || 0 >= scope.size()) {
			return;
		}
		for(String param : scope) {
			try {
				Field field = srcClass.getDeclaredField(param);
				field.setAccessible(true);
				if(!field.getType().getSimpleName().equals("String")) {
					continue;
				}
				Object val = field.get(source);
				if(null == val) {
					continue;
				}
				String valStr = String.valueOf(val);
				if("".equals(valStr)) {
					continue;
				}
				if(0 == valStr.indexOf("(")) {
					continue;
				}
				valStr = valStr.replace(",", ")(");
				valStr = "(" + valStr + ")";
				field.set(source, valStr);
			} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
//				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 去掉params指点的属性的值中不是数字的字符
	 * @param source 源对象
	 * @param params 参数列表
	 */
	public static void compareObjRemoveNotnumber(Object source, List<String> params) {
		Class<?> srcClass = source.getClass();
		if(null == params || 0 >= params.size()) {
			return;
		}
		for(String param : params) {
			try {
				Field field = srcClass.getDeclaredField(param);
				field.setAccessible(true);
				if(!field.getType().getSimpleName().equals("String")) {
					continue;
				}
				Object val = field.get(source);
				if(null == val) {
					continue;
				}
				String valStr = String.valueOf(val);
				if("".equals(valStr)) {
					continue;
				}
				if(0 == valStr.indexOf("(")) {
					continue;
				}
				String ragex = "[^\\d|,]";
				valStr = valStr.replaceAll(ragex, "");
				field.set(source, valStr);
			} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
//				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 比较两个对象值不同的属性
	 * @param source 源对象
	 * @param target 目标对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 目标对象值被改变的参数名称
	 */
	public static List<String> compareObjDiffParams(Object source, Object target, List<String> scope, List<String> exclude) {
		List<String> params = new ArrayList<>();
		if (source == null || target == null) {
			return params;
		}
		if(!target.getClass().isAssignableFrom(source.getClass())) {
			return params;
		}
		Class<?> srcClass = source.getClass();
        Field[] fields = srcClass.getDeclaredFields();
        for (Field field : fields) {
        	if(null != exclude && !exclude.isEmpty() && exclude.contains(field.getName())) {
        		continue;
        	}
        	if(null != scope && !scope.isEmpty() && !scope.contains(field.getName())) {
        		continue;
        	}
        	field.setAccessible(true);
        	try {
        		Object sv = field.get(source);
        		Object tv = field.get(target);
        		if(null == tv && null == sv) {
					continue;
				}
				if(null != tv && null != sv) {
					if(tv.getClass().getSimpleName().equals(sv.getClass().getSimpleName())) {
						if(tv.equals(sv)) {
							continue;
						}
					} else {
						String tvStr = String.valueOf(tv);
						String valStr = String.valueOf(sv);
						if(tvStr.equals(valStr)) {
							continue;
						}
					}
				}
        		params.add(field.getName());
    		} catch (IllegalArgumentException | IllegalAccessException e) {
//    			e.printStackTrace();
    		}
		}
		return params;
	}
	
	/**
	 * 比较两个对象不同名的属性
	 * @param source 源对象
	 * @param target 目标对象
	 * @param scope 属性范围，处理列表中的属性
	 * @param exclude 排除属性，不处理列表中的属性
	 * @return 不同名的属性列表
	 */
	public static List<String> compareObjDiffPropertys(Object source, Object target, List<String> scope, List<String> exclude) {
		List<String> propertys = new ArrayList<>();
		if (source == null || target == null) {
			return propertys;
		}
		Class<?> srcClass = source.getClass();
		Class<?> tarClass = target.getClass();
		Field[] srcFields = srcClass.getDeclaredFields();
		Field[] tarFields = tarClass.getDeclaredFields();
		for(Field srcField : srcFields) {
			String key = srcField.getName();
			if(null != scope && !scope.isEmpty() && !scope.contains(key)) {
				continue;
			}
			if(null != exclude && !exclude.isEmpty() && exclude.contains(key)) {
				continue;
			}
			boolean diff = true;
			for(Field tarField : tarFields) {
				if (tarField.getName().equals(srcField.getName())) {
					diff = false;
					break;
				}
			}
			if(diff) {
				propertys.add(srcField.getName());
			}
		}
		return propertys;
	}
	
	/**
	 * 比较两个BEAN或MAP对象的值是否相等
	 * 如果是BEAN与MAP对象比较时MAP中的key值应与BEAN的属性值名称相同且字段数目要一致
	 * 
	 * @param source 源对象
	 * @param target 目标对象
	 * @return true: 相等；false：不相等
	 */
	public static boolean compareObj(Object source, Object target) {
		if (source == null || target == null) {
			return false;
		}
		boolean rv = true;
		if (source instanceof Map) {
			rv = mapOfSrc(source, target, rv);
		} else {
			rv = classOfSrc(source, target, rv);
		}
		return rv;
	}
	
    @SuppressWarnings("unchecked")
	private static boolean mapOfSrc(Object source, Object target, boolean rv) {
        Map<String, Object> map = (Map<String, Object>) source;
        if(target instanceof Map) {
        	return source.equals(target);
        }
        Class<?> targetClass = target.getClass();
        Field[] fields = targetClass.getDeclaredFields();
        for (Field field : fields) {
        	if("id".equals(field.getName())) {
        		continue;
        	}
        	if(!map.containsKey(field.getName())) {
        		continue;
        	}
        	Object tarValue = getClassValue(target, field);
        	if(null == tarValue) {
        		rv = tarValue == map.get(field.getName());
        	}
        	if(null != tarValue && !tarValue.equals(map.get(field.getName()))) {
        		rv = false;
        	}
        	if(!rv) {
        		break;
        	}
        }
        return rv;
    }
    
	@SuppressWarnings("unchecked")
	private static boolean classOfSrc(Object source, Object target, boolean rv) {
        Class<?> srcClass = source.getClass();
        Field[] fields = srcClass.getDeclaredFields();
        for (Field field : fields) {
        	if("id".equals(field.getName())) {
        		continue;
        	}
        	if(target instanceof Map) {
        		Map<String, Object> tarMap = (Map<String, Object>) target;
        		if(!tarMap.containsKey(field.getName())) {
        			rv = false;
        			break;
        		}
        		Object srcValue = getClassValue(source, field);
        		if(null == srcValue) {
        			rv = srcValue == tarMap.get(field.getName());
        		}
        		if(null != srcValue && !srcValue.equals(tarMap.get(field.getName()))) {
        			rv = false;
        		}
        		if(!rv) {
        			break;
        		}
        	} else {
        		if(!target.getClass().isAssignableFrom(source.getClass())) {
        			rv = false;
        			break;
        		}
        		Object srcValue = getClassValue(source, field);
        		Object targetValue = getClassValue(target, field);
        		if(null == srcValue) {
        			rv = srcValue == targetValue;
        		}
        		if(null != srcValue && !srcValue.equals(targetValue)) {
        			rv = false;
        		}
        		if(!rv) {
        			break;
        		}
        	}
        }
       return rv;
    }
	
	/**
	 * 从对象中取值
	 * @param obj 对象
	 * @param field 字段
	 * @return 值
	 */
    private static Object getClassValue(Object obj, Field field) {
        if (obj == null) {
            return null;
        }
        field.setAccessible(true);
		try {
			return field.get(obj);
		} catch (IllegalArgumentException | IllegalAccessException e) {
//			e.printStackTrace();
		}
		return null;
    }
	
	/**
     * 根据字段名称取值
     * @param obj 对象
     * @param fieldName 字段名称
     * @return 值
     */
    public static Object getFieldValueByName(String fieldName, Object obj) {  
    	Class<?> objClass = obj.getClass();
		try {
			Field field = objClass.getDeclaredField(fieldName);
			field.setAccessible(true);
			return field.get(obj);
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
//			e.printStackTrace();
		}
		return null;
    }

	/**
     * 根据字段名称取值
     * @param obj 对象
     * @param fieldName 字段名称
	 * @param valueType 需要的结果类型
	 * @param <T> 泛型结果类型
     * @return 值
     */
    public static <T> T getFieldValueByName(String fieldName, Object obj, Class<T> valueType) {
		Object oval = getFieldValueByName(fieldName, obj);
		if (valueType.isInstance(oval)) {
			return valueType.cast(oval);
		}
		String str = (oval instanceof String) ? (String) oval : String.valueOf(oval);
		if (Long.class.isAssignableFrom(valueType)) {
			try {
				return valueType.cast(Long.parseLong(str));
			} catch (NumberFormatException e) {
				return null;
			}
		}
		if (Integer.class.isAssignableFrom(valueType)) {
			try {
				return valueType.cast(Integer.parseInt(str));
			} catch (NumberFormatException e) {
				return null;
			}
		}
		if (String.class.isAssignableFrom(valueType)) {
			try {
				return valueType.cast(str);
			} catch (NumberFormatException e) {
				return null;
			}
		}
		return null;
    }
    
    /**
     * 根据字段名称设置值
     * @param fieldName 字段名称
     * @param obj 对象
     * @param value 值
     */
    public static void setFieldValueByName(String fieldName, Object obj, Object value) {  
    	Class<?> objClass = obj.getClass();
    	try {
			Field field = objClass.getDeclaredField(fieldName);
			field.setAccessible(true);
			if (field.getType().equals(Long.class) && (value instanceof Integer)) {
				value = Long.valueOf(String.valueOf(value));
			}
			field.set(obj, value);
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
//			e.printStackTrace();
		}
	}
}
